﻿using System;
using System.Linq;
using MathService.DSP.Signals;

namespace MathService.DSP
{
    ///<summary>Цифровой фильтр</summary>
    public abstract class DigitalFilter
    {
        /// <summary>Встроенная линия задержки</summary>
        protected DelayLine f_DelayLine;

        /// <summary>Порядок фильтра</summary>        
        public int Order { get { return f_DelayLine.Length; } }


        protected DigitalFilter(int Order) { Initialize(Order); }

        /// <summary>Инициализация начального состояния фильтра</summary>
        public virtual void Initialize()
        {
            f_DelayLine.Initialize();
        }

        /// <summary>Инициализация фильтра с изменением порядка</summary>
        /// <param name="Order">Порядок фильтра</param>
        protected void Initialize(int Order)
        {
            f_DelayLine = new DelayLine(Order);
        }

        /// <summary>Обработка сигнала</summary>
        /// <param name="x">Входное воздействие в виде отсчётов сигнала</param>
        /// <returns>Массив отсчётов отклика фильтра</returns>        
        public double[] ProcessSignal(double[] x)
        {
            return x.Select(Process).ToArray();
        }

        /// <summary>обработка входного воздействия в виде цифрового сигнала</summary>
        /// <param name="s">Входное воздействия в виде цифрового сигнала</param>
        /// <returns>Отклик фильтра в виде цифрового сигнала</returns>
        public DigitalSignal ProcessSignal(DigitalSignal s)
        {
            return new DigitalSignal(s.dx, s.x0, s.Length, Process);
        }

        /// <summary>Получить импульсную характеристику фильтра</summary>
        /// <param name="dt">Период дискретизации сигнала</param>
        /// <param name="Length">Длительность сигнала</param>
        /// <returns>Импульсная характеристика фильтра</returns>
        public DigitalSignal GetImpulsCharactrristic(double dt, double Length)
        {
            var lv_DeltaFunction = DigitalSignal.Standart.DeltaFunction(dt, Length);
            var lv_Line = f_DelayLine;
            f_DelayLine = new DelayLine(f_DelayLine.Length);
            var lv_ImpulsCharactrristic = ProcessSignal(lv_DeltaFunction);
            f_DelayLine = lv_Line;
            return lv_ImpulsCharactrristic;
        }

        public double[] GetImpulsCharactrristic(int Length)
        {
            var lv_DelayLine = f_DelayLine;
            f_DelayLine = new DelayLine(lv_DelayLine.Length);
            var h = new double[Length];
            h[0] = 1;
            return h.Initialize(i => Process(h[i]));
        }

        public abstract double Process(double x_n);
    }
}